package a39;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.GenericApplicationContext;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

@Configuration
public class A39_1 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        System.out.println("1.设置BeanDefinition 获取源");
        SpringApplication application = new SpringApplication(A39_1.class);
        Set set = new HashSet();
        set.add("classpath:b01.xml"); //除了上面指定的A39_1为beanDefinition的源，这里又指定了一个xml文件为源
        application.setSources(set);


        System.out.println("2.推断应用类型");
        //点进入SpringApplication的构造函数，可以看到推断应用类型的逻辑.如果在类路径下找到servlet相关的类，就会推断为web服务的类型(SERVLET)
        Method deduceFromClasspath = WebApplicationType.class.getDeclaredMethod("deduceFromClasspath");
        deduceFromClasspath.setAccessible(true);
        System.out.println("\t应用类型为:"+deduceFromClasspath.invoke(null)); //静态方法的反射调用不需要传对象，null即可


        System.out.println("3.设置ApplicationContext 初始化器");
        //感觉了解即可，构造函数里会读取一些初始化器，我们这里自己添加一个自定义初始化器。初始化器应该就是在ApplicationContext.refresh之前调用，对ApplicationContext做一些初始化或者拓展的功能
        application.addInitializers(applicationContext -> {
            if (applicationContext instanceof GenericApplicationContext) {
                System.out.println("\t初始化器执行");
                ((GenericApplicationContext)applicationContext).registerBean("bean3", Bean3.class);
            }
        });


        System.out.println("4. 设置监听器");
        //构造函数时会读取一些监听器，这里我们也手动添加一个监听器。可以监听到spring的一些时间.哪些实践可以看看日志，事件类型还不少
        application.addListeners(event -> System.out.println("\t事件为:" + event.getClass()));


        System.out.println("5. 主类推断");
        Method deduceMainApplicationClass = SpringApplication.class.getDeclaredMethod("deduceMainApplicationClass");
        deduceMainApplicationClass.setAccessible(true);
        System.out.println("\t主类是："+deduceMainApplicationClass.invoke(application));

        ConfigurableApplicationContext context = application.run(args);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);

        }

        context.close();

    }

    static class Bean2 {

    }

    static class Bean3 {

    }

    @Bean
    public TomcatServletWebServerFactory servletWebServerFactory() {
        return new TomcatServletWebServerFactory();
    }

    @Bean
    public Bean2 bean2() {
        return new Bean2();
    }

    static class Bean1 {

    }
}
